JavaScript 变量申明解析
var属性有多种需要注意的特性:
- 无块级作用域
- 不带申明类型默认为全局变量
- 变量提升
- 运行重新申明变量
一、块级作用域
首先,js中申明的var变量或是方法,都没有块级作用域,只有函数作用域,最典型的示例为:
for (var i = 0; i < 100; i++){
// ...
}
console.log(i); // 输入100
若我们使用es6的let与const,就不会出现这种问题。
二、影响全局
若申明变量不使用变量类型,即使写在另一个函数作用域中申明的变量,也会直接将变量挂载在全局对象上,最容易引发此错误的地方在于使用with的时候,with可以延展一个对象的作用域链,将一个作用域的链拼接到执行上下文的作用域链中,相当于延长了当前作用域链:
const obj = {
a: 'a',
b: 'b',
};
with (obj) {
console.log(a, b); // a b
b = 3;
c = 1;
}
console.log(obj.b, c); // 3 1
在with作用域中可以直接访问到b的值, 但是我们假如书写错误或是记漏变量名,如对c进行操作,则会创建一个全局变量c,这样不但会污染全局空间,也会对系统造成额外的开销,让我们来测试一段使用with语句进行访问的测试代码:
const testobj = { foo: 'bar' };
let value;
let starttime;
let endtime;
const times = 1000000;
starttime = new Date().getTime();
for (let n = 0; n < times; n++) {
value = testobj.foo;
}
endtime = new Date().getTime();
console.log(`正常赋值操作:${endtime - starttime}ms`);
starttime = new Date().getTime();
with (testobj) {
for (let n = 0; n < times; n++) {
value = foo;
}
}
endtime = new Date().getTime();
console.log(`with赋值操作:${endtime - starttime}ms`);
*****输出结果
正常赋值操作:25ms
with赋值操作:415ms
造成的原因是因为,在with下进行访问变量默认都是从一个对象中进行访问, 这样比直接访问多一个层级,自然速度就慢下来了,而且with语句不利于编译器进行静态分析,以此我们在代码中不要使用with。